﻿// -----------------------------------------------------------------------
// <copyright file="RestClientMessageFormatter.cs" company="Spardo, LLC">
// Copyright (c) 2011 SPardo, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a 
// copy of this software and associated documentation files (the "Software"), 
// to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the 
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included 
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
// </copyright>
// -----------------------------------------------------------------------

namespace DotNet37Signals.Client
{
    using System.Linq;
    using System.Net;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    using System;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    internal class RestClientMessageFormatter : IClientMessageFormatter
    {
        IClientMessageFormatter Original { get; set; }
        OperationDescription Description { get; set; }
        RestWebContentTypeMapper Mapper { get; set; }
        ConnectionSettings Configuration { get; set; }

        public RestClientMessageFormatter(IClientMessageFormatter actual
            , OperationDescription description
            , RestWebContentTypeMapper mapper
            , ConnectionSettings configuration)
        {
            this.Original = actual;
            this.Description = description;
            this.Mapper = mapper;
            this.Configuration = configuration;
        }

        #region IClientMessageFormatter Members

        public object DeserializeReply(Message message, object[] parameters)
        {
            object output = null;

            var property = (WebBodyFormatMessageProperty)message.Properties["WebBodyFormatMessageProperty"];

            if (property.Format == WebContentFormat.Raw)
            {
                var response = (System.ServiceModel.Channels.HttpResponseMessageProperty)message.Properties["httpResponse"];

                switch (response.StatusCode)
                {
                    case HttpStatusCode.Created:
                        var location = response.Headers[HttpResponseHeader.Location] ?? string.Empty;
                        var id = location.Split('/').Last().Replace(".xml", string.Empty);
                        output = new NewEntity(id);
                        break;
                    case HttpStatusCode.OK:
                    default:
                        output = null;
                        break;
                }
            }
            else
            {
                var buffer = message.CreateBufferedCopy(int.MaxValue);

                var reader = buffer.CreateMessage().GetReaderAtBodyContents();
                reader.MoveToContent();

                if (reader.Name == "nil-classes")
                    output = Activator.CreateInstance(this.Mapper.ReturnType);
                
                if (output == null)
                    output = this.Original.DeserializeReply(buffer.CreateMessage(), parameters);

                buffer.Close();
            }

            return output;
        }

        public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
        {
            foreach (var parameter in parameters)
            {
                if (parameter is LegacyRequest)
                {
                    var legacy = (LegacyRequest)parameter;
                    if (string.IsNullOrEmpty(legacy.Token))
                        legacy.Token = this.Configuration.Credentials.Username;
                    break;
                }
            }


            this.Mapper.ReturnType = this.Description
                .Messages
                .First(m => m.Direction == MessageDirection.Output)
                .Body
                .ReturnValue
                .Type;

            var output = this.Original.SerializeRequest(messageVersion, parameters);

            return output;
        }

        #endregion
    }
}